package org.yray.sip.rtp.data;


import lombok.extern.slf4j.Slf4j;
import org.yray.sip.utils.ByteUtils;
import org.yray.sip.utils.CMG711;
import org.yray.sip.wav.WavFile;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import static org.yray.sip.rtp.sender.PacketInte.B_PCMA_MARK;


/**
 * @author lyg
 */
@Slf4j
public class MediaClient {
    private volatile  int beginSeq=0;
    private MediaChunk mediaChunk;
    public  static final int PCMA_SISE =160;
    private static final int PCMA_SISE_TO=320;
    private List<byte[]> tempData;
    private Long ssrc;
    private String callId;
    private volatile  Object lock = new Object();
    private static final byte[] BLANK_BYTE=new byte[PCMA_SISE_TO];

    static {
        Arrays.fill(BLANK_BYTE,(byte)0);
    }
    public  static final int STEP_WS=2;

    public String getCallId() {
        return callId;
    }

    public void setCallId(String callId) {
        this.callId = callId;
    }

    public MediaClient(Long ssrc,String callId)
    {
        mediaChunk=new MediaChunk();
        tempData =new ArrayList<>(0);
        this.ssrc=ssrc;
        this.callId=callId;
    }

    public int getBeginSeq() {
        return beginSeq;
    }

    public void setBeginSeq(int beginSeq) {
        this.beginSeq = beginSeq;
    }



    public void addPatchDate(byte[] bs)
    {
        int seq= ByteUtils.uBytes2Int(bs[2],bs[3]);

        if(bs[1]==B_PCMA_MARK)
        {
            synchronized (this) {
                if(getBeginSeq()!=0) {
                    return;
                }
                log.info("init begin,seq={}", seq);
                setBeginSeq(seq);
                doTempData();
            }
        }
        else if(getBeginSeq()==0)
        {
            tempData.add(bs);
            return;
        }

        int index=seq-getBeginSeq();
        if(index<0) {
            if(seq==0)
            {
                synchronized (lock) {
                    index=seq-getBeginSeq();
                    if(index<0&&seq==0)
                    {
                        setBeginSeq(getBeginSeq() - 65535);
                        log.info("以第一块序号把beginSeq递减65535,begin={}", getBeginSeq());
                        index = seq - getBeginSeq();
                    }
                }
            }
            log.info("seq={},begin={},序号回绕", seq, getBeginSeq());
        }
        byte[] addData=new byte[PCMA_SISE];
        System.arraycopy(bs,12,addData,0,PCMA_SISE);
        //解码
        addData= CMG711.decode(addData);
        mediaChunk.addData(index,addData);
    }



    private void doTempData()
    {
        for(byte[] bs:tempData)
        {
            addPatchDate(bs);
        }
        tempData.clear();
    }

    public void saveToFile(String fileName)
    {
        WavFile wavFile=new WavFile(fileName);
        MediaChunk read= mediaChunk;
        int fileLen=0;
        while (read!=null)
        {
            for(byte[] bs:read.getData())
            {
                if(bs==null)
                {
                    continue;
                }

                wavFile.write(bs);
                fileLen+=bs.length;
            }
            read=read.getNext();
        }
        wavFile.writeFileLen(fileLen);
        wavFile.close();
        log.info("saveToFile {} succ",fileName);
    }

    public byte[] getDataByStep(int step)
    {
        int begin=step*STEP_WS;
        int chunkNum=begin/MediaChunk.CHUNK_SIZE;
        int beginIndex= begin%MediaChunk.CHUNK_SIZE;

        MediaChunk pos=mediaChunk.getPos();
        while (pos!=null&&pos.getChunkNum()>chunkNum)
        {
            pos=pos.getPre();
        }
        while (pos!=null&&pos.getChunkNum()<chunkNum)
        {
           pos= pos.getNext();
        }
        byte[] ret=new byte[STEP_WS*PCMA_SISE_TO];
        Arrays.fill(ret,(byte)0);
        byte[][] data=pos.getData();

        for(int i=0;i<STEP_WS;i++)
        {
            byte[] packet=data[beginIndex+i];
            if(packet!=null) {
                System.arraycopy(packet, 0, ret, i * PCMA_SISE_TO, PCMA_SISE_TO);
            }
            else
            {
                data[beginIndex+i]=BLANK_BYTE;
                log.info("data[{}] is null ,step={},chunkNum={}",beginIndex+i,step,chunkNum);
            }
        }

       return ret;
    }

    public Long getSsrc() {
        return ssrc;
    }

    public void setSsrc(Long ssrc) {
        this.ssrc = ssrc;
    }
}
